package jsprintorbitor;


import java.util.ArrayList;
import java.util.List;

import sprinter.ISprinter;
import sprinter.ISprinter.GraphType;
import jsprintorbitor.bridge2native.BridgeUtils;
import jsprintorbitor.experiment.SpOrbDiaTtlExtractor;
import jsprintorbitor.experiment.SpOrbExperimentSettings;
import jsprintorbitor.experiment.graph.AlgGenPair;
import jsprintorbitor.experiment.graph.IGraphAlgorithm;
import jsprintorbitor.experiment.graph.IGraphGenerator;
import jsprintorbitor.style.SpOrbStyleFiller;
import laboratoryQ.LaboratoryQFront;
import laboratoryQ.experiment.reportage.ui.DefaultExperimentUIRenderer;
import laboratoryQ.experiment.reportage.ui.ExperimentReportage;
import laboratoryQ.experiment.reportage.ui.IExperimentUIRenderer;
import laboratoryQ.experiment.reportage.ui.diagram2component.ComponentList2TabbedPane;
import laboratoryQ.experiment.reportage.ui.diagram2component.Drawers2ComponentList;
import laboratoryQ.experiment.reportage.ui.diagram2component.IComponentExtractor;
import laboratoryQ.experiment.reportage.ui.diagram2component.IComponentListExtractor;
import laboratoryQ.experiment.settings.ReflectionBasedSettingsContainer;
import laboratoryQ.style.IStylizer;
import laboratoryQ.style.stages.ChainStylizerStylizer;

public class MainJSprintOrbitor {
	public static void main(String[] args) {
		/**
		 * dispose settings in finalize
		 */
		SpOrbExperimentSettings settings = new SpOrbExperimentSettings();
		settings.initialise();
		settings.randomSeed = 0;
		fillGraphTraversal(settings);
		fillShortestPath(settings);
		fillMaxFlow(settings);
		fillMinCostFlow(settings);
		settings.validate();

		ReflectionBasedSettingsContainer settCont =
			new ReflectionBasedSettingsContainer(settings);
		settCont.sortFields(new String[] {
				"randomSeed",

				"trvVirtualExpCasesEnabled",

				"gtrvexSzRngEnabled",
				"gtrvexSzRngVrtCntBeg",
				"gtrvexSzRngVrtCntEnd",
				"gtrvexSzRngExpRunCnt",
				"gtrvexSzRngV2EPower",
				"gtrvexSzRngV2EMul",
				"gtrvexSzRngV2EAdd",

				"gtrvexPwRngEnabled",
				"gtrvexPwRngVrtCnt",
				"gtrvexPwRngExpRunCnt",
				"gtrvexPwRngBeg",
				"gtrvexPwRngEnd",
				"gtrvexPwRngStep",
				"gtrvexPwRngMul",
				"gtrvexPwRngAdd",

				"dejkstraPwRngEnabled",
				"dejkstraPwRngVrtCnt",
				"dejkstraPwRngExpRunCnt",
				"dejkstraPwRngBeg",
				"dejkstraPwRngEnd",
				"dejkstraPwRngStep",
				"dejkstraPwRngMul",
				"dejkstraPwRngAdd",

				"dinicPwRngEnabled",
				"dinicPwRngVrtCnt",
				"dinicPwRngExpRunCnt",
				"dinicPwRngBeg",
				"dinicPwRngEnd",
				"dinicPwRngStep",
				"dinicPwRngMul",
				"dinicPwRngAdd",

				"mcfPwRngEnabled",
				"mcfPwRngVrtCnt",
				"mcfPwRngExpRunCnt",
				"mcfPwRngBeg",
				"mcfPwRngEnd",
				"mcfPwRngStep",
				"mcfPwRngMul",
				"mcfPwRngAdd",
		});

		SpOrbDiaTtlExtractor dtExtractor = new SpOrbDiaTtlExtractor();
		// TODO: stylizer here; may be use class ReportageSourceData ??
		ExperimentReportage experimentReportage = LaboratoryQFront.createDiagramsReportage(
				dtExtractor,
				dtExtractor,
				settCont,
				"Sprint Orbitor - graph library performance experiments"
			);

		ChainStylizerStylizer stylizer = getStylizer(experimentReportage);
		stylizer.getStylisersList().clear();
		stylizer.getStylisersList().add(new SpOrbStyleFiller());
		dtExtractor.setStylizer(stylizer);

		Drawers2ComponentList clextr = getCompExtractor(experimentReportage);
		clextr.setLegendExtractor(dtExtractor);

		LaboratoryQFront.showReportageFrame(null, experimentReportage);
	}

	private static void fillGraphTraversal(SpOrbExperimentSettings settings) {
		settings.trvVirtualExpCasesEnabled = true;

		settings.gtrvexSzRngEnabled = true;
		settings.gtrvexSzRngVrtCntBeg = 100;
		settings.gtrvexSzRngVrtCntEnd = 250;
		settings.gtrvexSzRngExpRunCnt = 60;
		settings.gtrvexSzRngV2EPower = 1.8;
		settings.gtrvexSzRngV2EMul = 2.5;
		settings.gtrvexSzRngV2EAdd = 30;

		settings.gtrvexPwRngEnabled = true;
		settings.gtrvexPwRngVrtCnt = 180;
		settings.gtrvexPwRngExpRunCnt = 60;
		settings.gtrvexPwRngBeg = 1.3;
		settings.gtrvexPwRngEnd = 2.1;
		settings.gtrvexPwRngStep = 0.01;
		settings.gtrvexPwRngMul = 2.5;
		settings.gtrvexPwRngAdd = 30;

		AlgGenPair[][] travExperimentCases = genTravExperimentCases();
		settings.traversalExperimentCases = travExperimentCases[0];
		settings.traversalExperimentCasesVirtual = travExperimentCases[1];
	}

	private static void fillShortestPath(SpOrbExperimentSettings settings) {
		settings.dejkstraPwRngEnabled = true;
		settings.dejkstraPwRngVrtCnt = 180;
		settings.dejkstraPwRngExpRunCnt = 60;
		settings.dejkstraPwRngBeg = 1.3;
		settings.dejkstraPwRngEnd = 2.1;
		settings.dejkstraPwRngStep = 0.01;
		settings.dejkstraPwRngMul = 2.5;
		settings.dejkstraPwRngAdd = 30;

		settings.shortestPathExperimentCases = genShortestPathExperimentCases();
	}

	private static void fillMaxFlow(SpOrbExperimentSettings settings) {
		settings.dinicPwRngEnabled = true;
		settings.dinicPwRngVrtCnt = 80;
		settings.dinicPwRngExpRunCnt = 30;
		settings.dinicPwRngBeg = 1.3;
		settings.dinicPwRngEnd = 2.1;
		settings.dinicPwRngStep = 0.05;
		settings.dinicPwRngMul = 2.5;
		settings.dinicPwRngAdd = 30;

		settings.maxFlowExperimentCases = genMaxFlowExperimentCases();
	}

	private static void fillMinCostFlow(SpOrbExperimentSettings settings) {
		settings.mcfPwRngEnabled = true;
		settings.mcfPwRngVrtCnt = 80;
		settings.mcfPwRngExpRunCnt = 30;
		settings.mcfPwRngBeg = 1.3;
		settings.mcfPwRngEnd = 1.8;
		settings.mcfPwRngStep = 0.01;
		settings.mcfPwRngMul = 2.5;
		settings.mcfPwRngAdd = 30;
		
		settings.minCostFlowExperimentCases = genMinCostFlowExperimentCases();
	}

// TODO: 2think: semantic is more than int

	private static AlgGenPair[][] genTravExperimentCases() {
		List<AlgGenPair> experimentCases = new ArrayList<AlgGenPair>();
		List<AlgGenPair> experimentCasesVirtual = new ArrayList<AlgGenPair>();
		ISprinter[] allSprinters = BridgeUtils.getAllSprinters();
		int n = allSprinters.length;
		int relevSprintersCount = 0;
		for (int i = 0; i < n; i++) {
			ISprinter sprinter = allSprinters[i];
			if (
					sprinter.getExperimentLabels().contains("graph-impl-compare") ||
					sprinter.getExperimentLabels().contains("CURRENT")
			) {
				relevSprintersCount++;
			}
		}
		int d0a = relevSprintersCount > 1 ? 0 : 1;
		int d1a = relevSprintersCount > 1 ? 1 : 0;
		int d0b = relevSprintersCount > 1 ? 1 : 0;
		int d1b = 0;
		int s0 = 0;
		int s1 = 0;
		for (int i = 0; i < n; i++) {
			ISprinter sprinter = allSprinters[i];
			if (
					sprinter.getExperimentLabels().contains("graph-impl-compare") ||
					sprinter.getExperimentLabels().contains("CURRENT")
			) {
				IGraphAlgorithm algorithm = sprinter.newBFSGraphTraversalAlgorithm();
				IGraphGenerator vectorGraphGen = sprinter.newEasyRandomGraphGenerator(GraphType.VECTOR);
				experimentCases.add(new AlgGenPair(
						algorithm,
						vectorGraphGen,
						s0, s1
				));
				s0 += d0a; s1 += d1a;
				IGraphGenerator matrixGraphGen = sprinter.newEasyRandomGraphGenerator(GraphType.MATRIX);
				experimentCases.add(new AlgGenPair(
						algorithm,
						matrixGraphGen,
						s0, s1
				));
				s0 += d0a; s1 += d1a;
				IGraphGenerator compactGen = sprinter.newEasyRandomGraphGenerator(GraphType.COMPACT);
				experimentCases.add(new AlgGenPair(
						algorithm,
						compactGen,
						s0, s1
				));
				s0 += d0a; s1 += d1a;
				IGraphGenerator nonstructedGen = sprinter.newEasyRandomGraphGenerator(GraphType.COMPACT_NOTSTRUCTED);
				experimentCases.add(new AlgGenPair(
						algorithm,
						nonstructedGen,
						s0, s1
				));
				s0 += d0a; s1 += d1a;
				IGraphGenerator igraphGen = sprinter.newEasyRandomGraphGenerator(GraphType.IGRAPH);
				experimentCasesVirtual.add(new AlgGenPair(
						algorithm,
						igraphGen,
						s0, s1
				));
				s0 += d0b; s1 += d1b; s1 = relevSprintersCount > 1 ? 0 : s1;
			}
		}
		return new AlgGenPair[][] {
				experimentCases.toArray(new AlgGenPair[experimentCases.size()]),
				experimentCasesVirtual.toArray(new AlgGenPair[experimentCasesVirtual.size()]),
			};
	}

	private static AlgGenPair[] genShortestPathExperimentCases() {
		List<AlgGenPair> experimentCases = new ArrayList<AlgGenPair>();
		ISprinter[] allSprinters = BridgeUtils.getAllSprinters();
		int n = allSprinters.length;
		for (int i = 0; i < n; i++) {
			ISprinter sprinter = allSprinters[i];
			if (
					sprinter.getExperimentLabels().contains("shortest-pach-experiment") ||
					sprinter.getExperimentLabels().contains("CURRENT")
			) {
				IGraphAlgorithm algorithm = sprinter.newDejkstraAlgorithm(0);
				experimentCases.add(new AlgGenPair(
						algorithm,
						sprinter.newEasyRandomGraphGenerator(GraphType.VECTOR),
						i, 0
				));
				experimentCases.add(new AlgGenPair(
						algorithm,
						sprinter.newEasyRandomGraphGenerator(GraphType.MATRIX),
						i, 1
				));
			}
		}
		return experimentCases.toArray(new AlgGenPair[experimentCases.size()]);
	}

	private static AlgGenPair[] genMaxFlowExperimentCases() {
		List<AlgGenPair> experimentCases = new ArrayList<AlgGenPair>();
		ISprinter[] allSprinters = BridgeUtils.getAllSprinters();
		int n = allSprinters.length;
		for (int i = 0; i < n; i++) {
			ISprinter sprinter = allSprinters[i];
			if (
					sprinter.getExperimentLabels().contains("max-flow-experiment") ||
					sprinter.getExperimentLabels().contains("CURRENT")
			) {
				IGraphAlgorithm algorithm = sprinter.newDinicAlgorithm(0, 1);
				experimentCases.add(new AlgGenPair(
						algorithm,
						sprinter.newFlowGraphGenerator(GraphType.VECTOR),
						i, 0
				));
			}
		}
		return experimentCases.toArray(new AlgGenPair[experimentCases.size()]);
	}

	private static AlgGenPair[] genMinCostFlowExperimentCases() {
		List<AlgGenPair> experimentCases = new ArrayList<AlgGenPair>();
		ISprinter[] allSprinters = BridgeUtils.getAllSprinters();
		int n = allSprinters.length;
		for (int i = 0; i < n; i++) {
			ISprinter sprinter = allSprinters[i];
			if (
					sprinter.getExperimentLabels().contains("min-cost-flow-experiment") ||
					sprinter.getExperimentLabels().contains("CURRENT")
			) {
				IGraphAlgorithm algorithm = sprinter.newMinCostFlowAlgorithm(0, 1);
				experimentCases.add(new AlgGenPair(
						algorithm,
						sprinter.newCostFlowGraphGenerator(GraphType.VECTOR),
						i, 0
				));
			}
		}
		return experimentCases.toArray(new AlgGenPair[experimentCases.size()]);
	}

	// TODO: may be move 2 laboratoryq
	private static ChainStylizerStylizer getStylizer(ExperimentReportage erep) {
		IExperimentUIRenderer irenderer =			erep.getExperimentUIRenderer();
		DefaultExperimentUIRenderer renderer =		(DefaultExperimentUIRenderer) irenderer;
		IComponentExtractor icextr =				renderer.getComponentExtractor();
		ComponentList2TabbedPane cextr =			(ComponentList2TabbedPane) icextr;
		IStylizer istylizer =						cextr.getStylizer();
		ChainStylizerStylizer stylizer =			(ChainStylizerStylizer) istylizer;
		return stylizer;
	}
	
	// TODO: may be move 2 laboratoryq
	private static Drawers2ComponentList getCompExtractor(ExperimentReportage erep) {
		IExperimentUIRenderer irenderer =			erep.getExperimentUIRenderer();
		DefaultExperimentUIRenderer renderer =		(DefaultExperimentUIRenderer) irenderer;
		IComponentExtractor icextr =				renderer.getComponentExtractor();
		ComponentList2TabbedPane cextr =			(ComponentList2TabbedPane) icextr;
		IComponentListExtractor iclextr =			cextr.getComponentListExtractor();
		Drawers2ComponentList clextr =				(Drawers2ComponentList) iclextr;
		return clextr;
	}
}
